﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using Furion.DynamicApiController;

#endregion

namespace Neto.PermissionGenerate;

public class PgHelper
{
    /// <summary>
    ///     获取菜单功能
    /// </summary>
    /// <returns></returns>
    public static List<PgItem> GetMvcMenus()
    {
        // var types = App.Assemblies.SelectMany(o => o.GetTypes()
        //     .Where(type => typeof(Controller).IsAssignableFrom(type)
        //                    || type.GetInterfaces().Contains(typeof(IDynamicApiController)))
        // );

        var types = App.EffectiveTypes
                .Where(type => typeof(Controller).IsAssignableFrom(type))
            ;
        //return GetMenus(types, "Admin");


        var AllMenus = new List<PgItem>();

        //遍历所有controller
        foreach (var controller in types)
        {
            //验证Controller是否贴了 AuthorityControllerAttribute
            if (controller.GetCustomAttributes()
                .All(o => o is not PgAreaAttribute && o is not PgMvcControllerAttribute)) continue;

            //区域属性
            var areaAttribute =
                controller.GetCustomAttributes().First(o => o is PgAreaAttribute) as PgAreaAttribute;

            var area = areaAttribute?.Area ?? "HtAdmin";

            //var areaName = areaAttribute.Area; //默认为HtAdmin
            var controllerName = controller.Name.RemoveLastStr("Controller"); // 移除Controller控制器名称
            //var controllerDescription = ""; //Controller 描述


            var controllerMenu = new PgItem();
            PgMvcControllerAttribute? controllerAttribute = null;

            #region 添加菜单目录（控制器）

            {
                if (controller.GetCustomAttributes().Any(o => o is PgMvcControllerAttribute))
                {
                    controllerAttribute =
                        controller.GetCustomAttributes().First(o => o is PgMvcControllerAttribute) as
                            PgMvcControllerAttribute;

                    controllerMenu = controllerAttribute.Adapt<PgItem>();
                    //menuController.IsControllerCatalogue = true; // 是否控制器目录,后台菜单目录结构不考虑这层

                    if (!string.IsNullOrWhiteSpace(controllerAttribute.Controller))
                        controllerName = controllerAttribute.Controller;
                    //if (!string.IsNullOrWhiteSpace(controllerAttribute.Area)) areaName = controllerAttribute.Area;
                    // if (!string.IsNullOrWhiteSpace(controllerAttribute.ControllerDescription))
                    //     controllerDescription = controllerAttribute.ControllerDescription;
                    // else
                    //     controllerDescription = controllerAttribute.Controller;

                    controllerMenu.Code = $"{area}_{controllerName}_Controller";
                    controllerMenu.Area = area;
                    controllerMenu.Controller = controllerName;
                    //controllerMenu.ControllerDescription = controllerDescription;
                    //controllerMenu.Icon = string.IsNullOrWhiteSpace(controllerMenu.Icon)
                    //    ? "layui-icon-link"
                    //    : controllerMenu.Icon;
                    controllerMenu.Route = $"{area}/{controllerName}";

                    controllerMenu.MenuPCode = controllerAttribute.MenuPCode.Trim();

                    AllMenus.Add(controllerMenu);
                }
            }

            #endregion 添加菜单目录（控制器）

            // //菜单父级
            // var menuParentAttribute =
            //     controller.GetCustomAttributes().FirstOrDefault(o => o is MenuMenuParentAttribute) as
            //         MenuMenuParentAttribute;
            // //菜单的父级代码
            // var menuPCode = menuParentAttribute?.MenuPCode ?? "HtAdmin";

            #region 菜单

            #region 【菜单】 获取 控制器 上的 菜单信息

            {
                var menuAttributes = controller.GetCustomAttributes().Where(o => o is PgMvcMenuAttribute);
                foreach (var attribute in menuAttributes)
                {
                    var menuAttribute = (PgMvcMenuAttribute)attribute;
                    //AddMenuItem(menuAttribute);
                    var menu = controllerMenu.Adapt<PgItem>();
                    menu.Area = area;
                    menu.Controller = controllerName;


                    menu.PgType = PgType.Menu;
                    menu.Name = menuAttribute.Name;
                    //menu.MenuActionCode = actionCode;

                    // menu.AuthActions = methodInfo.Name;
                    // menu.Action = methodInfo.Name;
                    menu.IsMenuAction = true;
                    AllMenus.Add(menu);
                }
            }

            #endregion 【菜单】 获取 控制器 上的 菜单信息

            //var menus = new List<AuthorityMenuItem>();

            #region 【菜单】 获取Method上的 菜单信息

            foreach (var methodInfo in controller.GetMethods())
            {
                var actionCode = $"{area}_{controllerName}_Action_{methodInfo.Name}";

                //if (methodInfo.GetCustomAttributes().Any(o => o is AuthorityMenuAttribute))
                //{
                //    var menuAttribute = methodInfo.GetCustomAttributes().First(o => o is AuthorityMenuAttribute) as AuthorityMenuAttribute;
                foreach (PgMvcMenuAttribute menuAttribute in methodInfo.GetCustomAttributes()
                             .Where(o => o is PgMvcMenuAttribute))
                {
                    #region 菜单

                    //AddMenuItem(menuAttribute, methodInfo.Name);
                    var menu = menuAttribute.Adapt<PgItem>();

                    menu.Area = area;
                    menu.Controller = controllerName;


                    menu.PgType = PgType.Menu;
                    menu.Name = menuAttribute.Name;
                    menu.ActionCode = actionCode;
                    if (!string.IsNullOrWhiteSpace(menuAttribute.Code))
                        //如果设置了Code，则使用Code
                        menu.Code = $"{area}_{controllerName}_Menu_{menuAttribute.Code}";
                    else
                        //如果没有设置Code，则使用方法名(action 名称)
                        menu.Code = $"{area}_{controllerName}_Menu_{methodInfo.Name}";

                    //menu.PgType = PgType.Menu1;
                    //默认url：Ht
                    if (string.IsNullOrWhiteSpace(menuAttribute.Route))
                    {
                        menu.Route = $"{area}/{controllerName}/{methodInfo.Name}";
                        //组装 url 参数
                        if (!string.IsNullOrWhiteSpace(menuAttribute.UrlPars))
                            menu.Route = $"{menu.Route}?{menuAttribute.UrlPars.TrimStart('?')}";
                    }

                    //如果未设置PCode，则默认使用Controller属性的PCode,如果设置了就用菜单的
                    if (!string.IsNullOrWhiteSpace(menuAttribute.MenuPCode))
                        menu.MenuPCode = menuAttribute.MenuPCode.Trim();
                    else
                        menu.MenuPCode = controllerMenu.Code;

                    menu.AuthActions = methodInfo.Name;
                    menu.Action = methodInfo.Name;
                    menu.IsMenuAction = true;
                    AllMenus.Add(menu);

                    #endregion
                }

                foreach (var attribute in methodInfo.GetCustomAttributes()
                             .Where(o => o is PgMvcActionAttribute))
                {
                    var functionAttribute = (PgMvcActionAttribute)attribute;

                    #region 功能Action

                    //AddMenuItem(menuAttribute, methodInfo.Name);
                    //AddMenuItem(menuAttribute, methodInfo.Name);
                    var function = functionAttribute.Adapt<PgItem>();

                    function.Area = area;
                    function.Controller = controllerName;

                    function.PgType = PgType.Action;
                    function.Name = functionAttribute.Name;
                    function.Code = actionCode;
                    function.MenuPCode = controllerMenu.Code;
                    function.Route = $"{area}/{controllerName}/{methodInfo.Name}";
                    function.Action = methodInfo.Name;
                    if (string.IsNullOrWhiteSpace(function.AuthActions)) function.AuthActions = methodInfo.Name;

                    //判断Action是否贴了MenuAttribute
                    if (methodInfo.GetCustomAttributes()
                        .Any(o => o is PgMvcMenuAttribute))
                        function.IsMenuAction = true;


                    AllMenus.Add(function);

                    #endregion
                }
            }

            #endregion 【菜单】 获取Method上的 菜单信息

            #endregion 菜单
        }

        return AllMenus;
    }

    /// <summary>
    ///     获取菜单功能
    /// </summary>
    /// <returns></returns>
    public static List<PgItem> GetApiMenus()
    {
        // var types = App.Assemblies.SelectMany(o => o.GetTypes()
        //     .Where(type => typeof(Controller).IsAssignableFrom(type)
        //                    || type.GetInterfaces().Contains(typeof(IDynamicApiController)))
        // );

        var types = App.EffectiveTypes
            .Where(type => typeof(Controller).IsAssignableFrom(type)
                           || typeof(ControllerBase).IsAssignableFrom(type)
                           || type.GetInterfaces().Contains(typeof(IDynamicApiController)));


        var allMenus = new List<PgItem>();

        //遍历所有controller
        foreach (var controller in types)
        {
            //验证Controller是否贴了 PgApiControllerAttribute,如果没有贴，则跳过
            if (controller.GetCustomAttributes().All(o => o is not PgApiControllerAttribute)) continue;

            //区域属性
            var areaAttribute =
                controller.GetCustomAttributes().First(o => o is PgAreaAttribute) as PgAreaAttribute;

            //如果没有设置Area，则使用默认值Api
            var area = areaAttribute?.Area ?? "Api";

            //获取控制器名称，并且去除Controller后缀，去除Service后缀，去除Services后缀,Area的前缀
            var controllerName = controller.Name.RemoveLastStr("Controller").RemoveLastStr("Service")
                .RemoveLastStr("Services").RemoveStartStr(area);


            var controllerItem = new PgItem();

            //获取控制器属性
            PgApiControllerAttribute? controllerAttribute = null;

            #region 【Controller】添加控制器

            {
                //获取控制器属性,如果有则添加到菜单中
                if (controller.GetCustomAttributes().Any(o => o is PgApiControllerAttribute))
                {
                    controllerAttribute =
                        controller.GetCustomAttributes().First(o => o is PgApiControllerAttribute) as
                            PgApiControllerAttribute;
                    if (controllerAttribute != null)
                    {
                        controllerItem = controllerAttribute.Adapt<PgItem>();
                        controllerItem.Area = area;
                        controllerItem.Code = $"{area}_{controllerName}_Controller";
                        controllerItem.ControllerCode = controllerItem.Code;
                        //menuController.IsControllerCatalogue = true; // 是否控制器目录,后台菜单目录结构不考虑这层

                        //如果未设置PCode，则默认使用Area
                        if (controllerItem.MenuPCode.IsNullOrWhiteSpace()) controllerItem.MenuPCode = area;

                        //controller 如果未设置AutoAuthApiControllerAttribute的Controller，则使用默认控制器名称
                        var customerControllerName = controllerAttribute.Controller.IsNullOrWhiteSpace()
                            ? controllerName
                            : controllerAttribute.Controller;

                        controllerItem.Controller = customerControllerName;

                        //controllerMenu.Icon = string.IsNullOrWhiteSpace(controllerMenu.Icon)
                        //    ? "layui-icon-link"
                        //    : controllerMenu.Icon;
                        controllerItem.Route = $"{area}/{controllerItem.Controller}";

                        allMenus.Add(controllerItem);
                    }
                }
            }

            #endregion 【Controller】添加控制器

            #region 【Menu】 控制器->菜单

            {
                var menuAttributes = controller.GetCustomAttributes().Where(o => o is PgApiMenuAttribute);
                foreach (var attribute in menuAttributes)
                {
                    var menuAttribute = (PgApiMenuAttribute)attribute;
                    //AddMenuItem(menuAttribute);
                    var menu = menuAttribute.Adapt<PgItem>();
                    menu.Area = area;
                    if (string.IsNullOrWhiteSpace(menuAttribute.Code)) menu.Code = menu.UrlKey;
                    //如果未设置Area，则默认使用控制器的Area
                    if (menuAttribute.Area.IsNullOrWhiteSpace()) menu.Area = controllerItem.Area;
                    menu.Code = $"{area}_{controllerName}_Menu_{menu.Code}";
                    menu.ControllerCode = controllerItem.Code;
                    menu.Controller = controllerItem.Controller;
                    menu.Name = menuAttribute.Name;
                    //如果未设置PCode，则默认使用Area
                    if (menu.MenuPCode.IsNullOrWhiteSpace()) menu.MenuPCode = area;

                    //API的菜单应该没有路由
                    //menu.RouteUrl = $"{area}/{controllerItem.Controller}/{menuAttribute.Code}/{}";
                    allMenus.Add(menu);
                }
            }

            #endregion 【Menu】 控制器->菜单

            #region 【Action】 获取Method上的 菜单信息

            foreach (var methodInfo in controller.GetMethods())
            {
                var actionCode = $"{area}_{controllerName}_Action_{methodInfo.Name}";

                foreach (var attribute in methodInfo.GetCustomAttributes()
                             .Where(o => o is PgApiActionAttribute))
                {
                    var functionAttribute = (PgApiActionAttribute)attribute;

                    #region 功能Action

                    //AddMenuItem(menuAttribute, methodInfo.Name);
                    //AddMenuItem(menuAttribute, methodInfo.Name);
                    var function = functionAttribute.Adapt<PgItem>();


                    function.Area = area;
                    function.ControllerCode = controllerItem.Code;
                    function.Controller = controllerItem.Controller;
                    function.Code = $"{area}_{controllerName}_Action_{methodInfo.Name}";

                    function.PgType = PgType.Action;
                    function.Name = functionAttribute.Name;
                    function.IsLoginOnly = functionAttribute.IsLoginOnly;
                    function.Sort = functionAttribute.Sort;
                    function.Code = actionCode;
                    function.MenuPCode = controllerItem.Code;
                    function.Route = $"{area}/{controllerName}/{methodInfo.Name}";

                    //如果未设置Action，则默认为方法名
                    if (function.Action.IsNullOrWhiteSpace()) function.Action = methodInfo.Name;

                    function.ActionCode = $"{area}_{controllerName}_{methodInfo.Name}";
                    //如果没有设置AuthActions，则默认为Action名
                    if (string.IsNullOrWhiteSpace(function.AuthActions)) function.AuthActions = function.Action;

                    allMenus.Add(function);

                    #endregion
                }
            }

            #endregion 【菜单】 获取Method上的 菜单信息
        }

        return allMenus;
    }


    private static PgItem GetMenu(PgMvcMenuAttribute pgPgMvcMenuAttribute,
        PgItem pgItem = null)
    {
        if (pgItem == null) pgItem = new PgItem();

        return pgItem;
    }

    private static void GetAreas(IEnumerable<Type> types)
    {
        var menuAreaTypes = App.Assemblies.SelectMany(o => o.GetTypes().AsEnumerable()
            .Where(type => typeof(PgAreaAttribute).IsAssignableFrom(type)
                           || type.GetInterfaces().Contains(typeof(PgAreaAttribute))));
        foreach (var type in menuAreaTypes)
        {
        }
    }
}